home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / cmdline.lha / cmdline / src / lib / cmdline.h < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-13  |  29.3 KB  |  914 lines

  1. //------------------------------------------------------------------------
  2. // ^FILE: cmdline.h - declare the basic classes used in the CmdLine library
  3. //
  4. // ^DESCRIPTION:
  5. //    This file declares the three basic classes used in the CmdLine library.
  6. //    These three classes are "CmdArg" (a command-argument object),
  7. //    "CmdLineArgIter" (an object to iterate over a set of arguments),
  8. //    and "CmdLine" (the command-line object itself).
  9. //
  10. // ^HISTORY:
  11. //    03/19/92    Brad Appleton    <brad@ssd.csd.harris.com>    Created
  12. //
  13. //    03/01/93    Brad Appleton    <brad@ssd.csd.harris.com>
  14. //    - Added arg_sequence field to CmdArg
  15. //    - Added cmd_nargs_parsed field to CmdLine
  16. //    - Added cmd_description field to CmdLine
  17. //    - Added exit_handler() and quit() member-functions to CmdLine
  18. //    - Added ALLOW_PLUS to list of CmdLine configuration flags
  19. //-^^---------------------------------------------------------------------
  20.  
  21. #ifndef _usr_include_cmdline_h
  22. #define _usr_include_cmdline_h
  23.  
  24. class  ostream ;
  25. class  istream ;
  26. class  CmdLine ;
  27. class  CmdArgListIter ;
  28. class  CmdArgListList ;
  29.  
  30. //-----------------------------------------------------------------------------
  31.  
  32.    // A CmdArg is an abstract command-line argument.
  33.    // At this level (being the base class), all a command argument
  34.    // contains is the "interface" (on the command-line) of the
  35.    // argument, and some information (after the command-line has
  36.    // been parsed) that says "how" the argument appeared (if it did).
  37.    //
  38.    // The interface of a CmdArg consists of 6 things:
  39.    //    1) a character name
  40.    //    2) a keyword name
  41.    //    3) a value name (if the argument takes a value)
  42.    //    4) an argument description
  43.    //    5) a set of flags describing the syntax of the argument.
  44.    //    6) a set of flags to record how (and if) the argument
  45.    //         appeared on the command-line.
  46.    //
  47.    // When constructing a CmdArg, the most common syntax-flags can be
  48.    // inferred from the syntax used in the argument description,
  49.    // and the argument value name.  If the first non-white character
  50.    // of the argument description is ';', then the argument is considered
  51.    // to be "secret" and is NOT printed in usage messages.
  52.    //
  53.    // When specifiying a value, one may enclose the value name between
  54.    // '[' and ']' to indicate the value is optional. Also, one may follow
  55.    // the actual value name with "..." to indicate that the value corresponds
  56.    // to a LIST of values.
  57.    //
  58.    // Hence, the only time you really need to explicitly specify any syntax
  59.    // flags is when you want a value to be "strictly sticky" or "strictly
  60.    // separate"  and/or you want an argument to be able to be matched both
  61.    // positionally AND by (long or short) keyword.
  62.    //
  63. class  CmdArg {
  64. public:
  65.    friend class CmdLine ;
  66.  
  67.       // Flags that define the argument syntax
  68.    enum  CmdArgSyntax {
  69.       isOPT       = 0x00,  // argument is optional
  70.       isREQ       = 0x01,  // argument is required
  71.       isVALOPT    = 0x02,  // argument value is optional
  72.       isVALREQ    = 0x04,  // argument value is required
  73.       isVALSEP    = 0x08,  // argument value must be in a separate token
  74.       isVALSTICKY = 0x10,  // argument value must be in the same token
  75.       isLIST      = 0x20,  // argument is a list
  76.       isPOS       = 0x40,  // argument is positional
  77.       isHIDDEN    = 0x80,  // argument is not to be printed in usage
  78. #ifndef __gplusplus
  79.       isVALTAKEN  = (isVALREQ | isVALOPT),    // argument takes a value
  80.       isOPTVALOPT = (isOPT | isVALOPT),
  81.       isOPTVALREQ = (isOPT | isVALREQ),
  82.       isPOSVALOPT = (isPOS | isVALOPT),
  83.       isPOSVALREQ = (isPOS | isVALREQ),
  84. #else
  85.       isVALTAKEN  = 0x06,     // g++ doesnt seem to recognize enums that
  86.       isOPTVALOPT = 0x02,     // are defined in terms of previous values
  87.       isOPTVALREQ = 0x04,     // so I have to hard code the values instead.
  88.       isPOSVALOPT = 0x42,     //
  89.       isPOSVALREQ = 0x44,     // If this ever changes -- remove this stuff!
  90. #endif
  91.    } ;
  92.  
  93.      // Flags that say how the argument was specied on the command-line
  94.    enum  CmdArgFlags {
  95.       GIVEN      = 0x01,  // argument was given
  96.       VALGIVEN   = 0x02,  // argument value was given
  97.       OPTION     = 0x04,  // item was matched as an option
  98.       KEYWORD    = 0x08,  // item was matched as a keyword
  99.       POSITIONAL = 0x10,  // item was matched as a positional argument
  100.       VALSEP     = 0x20,  // value was in a separate token
  101.    } ;
  102.  
  103.       // Create an option that takes a value.
  104.       //
  105.       // The default flags are to assume that the argument is optional
  106.       // and that the value is required.
  107.       //
  108.       // Some examples:
  109.       //
  110.       //    CmdArg('c', "count", "number", "specify the # of copies to use);
  111.       //
  112.       //    CmdArg('d', "debug", "[level]". "turn on debugging and optionally"
  113.       //                                    "specify the debug level");
  114.       //
  115.       //    CmdArg('l', "list", "items ...", "specify a list of items.");
  116.       //
  117.    CmdArg(char         optchar,
  118.           const char * keyword,
  119.           const char * value,
  120.           const char * description,
  121.           unsigned     syntax_flags =isOPTVALREQ);
  122.  
  123.       // Create an option that takes no value.
  124.       //
  125.       // The default flags are to assume that the argument is optional.
  126.       //
  127.       // Some examples:
  128.       //
  129.       //    CmdArg('m', "mode", "turn on this mode");
  130.       //
  131.    CmdArg(char         optchar,
  132.           const char * keyword,
  133.           const char * description,
  134.           unsigned     syntax_flags =isOPT);
  135.  
  136.       // Create a positional argument.
  137.       //
  138.       // The default flags are to assume that the argument is positional
  139.       // and that the argument value is required.
  140.       //
  141.       // Some examples:
  142.       //
  143.       //    CmdArg("file", "file to read");
  144.       //
  145.       //    CmdArg("[file]", "optional file to read");
  146.       //
  147.       //    CmdArg("file ...", "list of files to read");
  148.       //
  149.       //    CmdArg("[file ...]", "optional list of files to read");
  150.       //
  151.    CmdArg(const char * value,
  152.           const char * description,
  153.           unsigned     syntax_flags =isPOSVALREQ);
  154.  
  155.  
  156.    CmdArg(const CmdArg & cp);
  157.  
  158.    virtual ~CmdArg(void);
  159.  
  160.       // over-ride this function to return a non-zero value if you
  161.       // wish the argument to be ignored (except for usage messages).
  162.       //
  163.    virtual  int
  164.    is_dummy(void);
  165.  
  166.       // Here is the "primary" function that makes everything work ...
  167.       //
  168.       // Whenever we actually "match" an argument on the command-line,
  169.       // we need to tell the argument it was matched (and how), and
  170.       // give it the string value (if there is one) to associate with it.
  171.       //
  172.       // At this point, the argument object is then responsible for
  173.       // performing whatever "magic" is to be done. This might be going
  174.       // off and reading a file, performing some other actions, or just
  175.       // "compiling" the argument into some internal value (specified
  176.       // by the derived class) to be queried at a later time.
  177.       //
  178.       // The parameters to this function are as follows:
  179.       //
  180.       //   PARAMETER 1: arg
  181.       //      The string value on the command-line to associate with this
  182.       //      argument. If this argument does not take a value, or the
  183.       //      value is optional and was NOT supplied, then NULL is passed.
  184.       //      This parameter is a reference parameter and before returning,
  185.       //      "arg" should either be set to NULL (to indicate that the entire
  186.       //      argument was used) or should point to the first unused character
  187.       //      of "arg".
  188.       //
  189.       //   PARAMETER 2: cmd
  190.       //      A reference to the command-line object that is currently being
  191.       //      parsed.  There are parts of this object that may be helpful in
  192.       //      determining what to do. In particular, we may want to look at
  193.       //      the "flags" of the command.  If the QUIET flag is set, then
  194.       //      this routine should suppress the printing of any error messages.
  195.       //      If the TEMP flag is set, then "arg" (the first parameter) points
  196.       //      to storage that may not be around for much longer and we may
  197.       //      want to make a copy of it.
  198.       //
  199.       // Before, this function is called, the CmdLine object that is parsing
  200.       // the arguments has already set the "flags()" of this argument to tell
  201.       // us how we appeared on the command-line this time around (were we
  202.       // specified as an option or positionally? Is "arg" in a separate argv[]
  203.       // element?).
  204.       //
  205.       // After we have done our "magic" and set the reference parameter
  206.       // "arg", this function should return a value of 0 if everything
  207.       // is A-OK and "arg" was a correctly specified value for this type of
  208.       // of argument. If something went wrong (like a syntax error in "arg"),
  209.       // then we should return a non-zero value.
  210.       //
  211.    virtual  int
  212.    operator()(const char * & arg, CmdLine & cmd) = 0;
  213.  
  214.       // Retrieve the syntax flags for this argument.
  215.    unsigned
  216.    syntax(void) const  { return  arg_syntax; }
  217.  
  218.       // Get the flags that say how this argument was specified.
  219.    unsigned
  220.    flags(void) const  { return  arg_flags; }
  221.  
  222.       // Get the sequence number corresponding to the last
  223.       // time this argument was matched on the command-line.
  224.       //
  225.       // If this argument was not matched, the sequence number
  226.       // will be zero, otherwise it will be 'N' where the last
  227.       // time this argument was matched, it was the 'N'th argument
  228.       // encountered.
  229.    unsigned
  230.    sequence(void) const { return arg_sequence; }
  231.  
  232.       // Get the character (short-option) name of this argument.
  233.       // Returns '\0' if there isnt one.
  234.    char
  235.    char_name(void) const  { return  arg_char_name; }
  236.  
  237.       // Get the keyword (long-option) name of this argument
  238.       // Returns NULL if there isnt one.
  239.    const char *
  240.    keyword_name(void) const  { return  arg_keyword_name; }
  241.  
  242.       // Get the value name of this argument.
  243.       // Returns NULL if this argument takes no value.
  244.    const char *
  245.    value_name(void) const  { return  arg_value_name; }
  246.  
  247.       // Get the description (help-message) of this argument.
  248.    const char *
  249.    description(void) const  { return  arg_description; }
  250.  
  251.       // If we were compiled for dubugging, then dump this argument
  252.    virtual  void
  253.    dump(ostream & os, unsigned level =0) const;
  254.  
  255. private:
  256.    // Member functions for internal use
  257.  
  258.    void
  259.    adjust_syntax(void);
  260.  
  261.    void
  262.    parse_description(void);
  263.  
  264.    void
  265.    parse_value(void);
  266.  
  267.    void
  268.    flags(unsigned newflags)  { arg_flags = newflags; }
  269.  
  270.    void
  271.    set(unsigned flags)  { arg_flags |= flags; }
  272.  
  273.    void
  274.    clear(unsigned flags =~0)  { arg_flags &= ~flags; }
  275.  
  276.       // set sequence number
  277.    void
  278.    sequence(unsigned  num) { arg_sequence = num; }
  279.  
  280.    // Private data members
  281.  
  282.    unsigned     alloc_value_name : 1 ;
  283.  
  284.    unsigned     arg_flags : 8 ;
  285.    unsigned     arg_syntax : 8 ;
  286.  
  287.    unsigned     arg_sequence;
  288.  
  289.    char         arg_char_name;
  290.    const char * arg_keyword_name;
  291.    const char * arg_value_name;
  292.    const char * arg_description;
  293. } ;
  294.  
  295. //-----------------------------------------------------------------------------
  296.  
  297.    // In order to parse arguments, we need to have an input source where
  298.    // the arguments are coming from.  CmdLineArgIter is an abstract
  299.    // iterator class for cycling through all the command-line arguments
  300.    // from an arbitrary input source.
  301.    //
  302. class  CmdLineArgIter {
  303. public:
  304.    CmdLineArgIter(void);
  305.  
  306.    virtual ~CmdLineArgIter(void);
  307.  
  308.       // Return the current argument and advance to the next one.
  309.       // Returns NULL if we are already at the end of the arguments
  310.       //
  311.    virtual const char *
  312.    operator()(void) = 0;
  313.  
  314.       // Are the args returned by operator() pointing to temporary storage?
  315.    virtual int
  316.    is_temporary(void) const = 0;
  317.  
  318. private:
  319.    CmdLineArgIter(const CmdLineArgIter &) ;
  320.  
  321.    CmdLineArgIter &
  322.    operator=(const CmdLineArgIter &) ;
  323. } ;
  324.  
  325.  
  326.    // CmdArgvIter is a class used to iterate through command arguments
  327.    // that come from an array of strings (like argv[] from main()).
  328.    //
  329. class  CmdArgvIter : public CmdLineArgIter {
  330. public:
  331.    CmdArgvIter(int argc, const char * const argv[])
  332.       : count(argc), array(argv), index(0) {}
  333.  
  334.    CmdArgvIter(const char * const argv[])
  335.       : array(argv), index(0), count(-1) {}
  336.  
  337.    virtual ~CmdArgvIter(void);
  338.  
  339.    virtual const char *
  340.    operator()(void);
  341.  
  342.       // is_temporary returns 0 for CmdArgvIter
  343.    virtual int
  344.    is_temporary(void) const;
  345.  
  346.       // Restart using a different string array.
  347.    void
  348.    reset(int argc, const char * const argv[])
  349.       { count = argc; array = argv; index = 0; }
  350.  
  351.    void
  352.    reset(const char * const argv[])
  353.       { array = argv; index = 0; count = -1; }
  354.  
  355. private:
  356.    CmdArgvIter(const CmdArgvIter &) ;
  357.  
  358.    CmdArgvIter &
  359.    operator=(const CmdArgvIter &) ;
  360.  
  361.    int   count;
  362.    int   index;
  363.    const char * const *  array;
  364. } ;
  365.  
  366.  
  367.    // CmdStrTok iterator is a class for iterating over arguments that
  368.    // are specified in a string of tokens that are delimited by a
  369.    // particular set of characters.  The strtok(3C) library function
  370.    // is used to extract tokens from the string.
  371.    //
  372.    // If NULL is given as the delimiter-set, then whitespace is assumed.
  373.    //
  374. class  CmdStrTokIter : public CmdLineArgIter {
  375. public:
  376.    CmdStrTokIter(const char * tokens, const char * delimiters =0);
  377.  
  378.    virtual ~CmdStrTokIter(void);
  379.  
  380.    virtual const char *
  381.    operator()(void);
  382.  
  383.       // Reset using a new token-string and delimiter set.
  384.    void
  385.    reset(const char * tokens, const char * delimiters =0);
  386.  
  387.       // Get the current delimiter set
  388.    const char *
  389.    delimiters(void) const { return  seps; }
  390.  
  391.       // Change the current delimiter set
  392.    void
  393.    delimiters(const char * new_delimiters)  { seps = new_delimiters; }
  394.  
  395.       // is_temporary returns 1 for CmdStrTokIter
  396.    virtual int
  397.    is_temporary(void) const;
  398.  
  399. private:
  400.    CmdStrTokIter(const CmdStrTokIter &) ;
  401.  
  402.    CmdStrTokIter &
  403.    operator=(const CmdStrTokIter &) ;
  404.  
  405.    char       * tokstr;
  406.    const char * seps;
  407.    const char * token;
  408. } ;
  409.  
  410.  
  411.    // CmdIstreamIter is a class for iterating over arguments that come
  412.    // from an input stream. Each line of the input stream is considered
  413.    // to be a set of white-space separated tokens. If the the first
  414.    // non-white character on a line is '#' ('!' for VMS systems) then
  415.    // the line is considered a comment and is ignored.
  416.    //
  417.    // *Note:: If a line is more than 1022 characters in length then we
  418.    // treat it as if it were several lines of length 1022 or less.
  419.    //
  420. class  CmdIstreamIter : public CmdLineArgIter {
  421. public:
  422.    static const unsigned  MAX_LINE_LEN ;
  423.  
  424. #ifdef vms
  425.    enum { c_COMMENT = '!' } ;
  426. #else
  427.    enum { c_COMMENT = '#' } ;
  428. #endif
  429.  
  430.    CmdIstreamIter(istream & input);
  431.  
  432.    virtual ~CmdIstreamIter(void);
  433.  
  434.    virtual const char *
  435.    operator()(void);
  436.  
  437.       // is_temporary returns 1 for CmdIstreamIter
  438.    virtual int
  439.    is_temporary(void) const;
  440.  
  441. private:
  442.    istream & is ;
  443.    CmdStrTokIter * tok_iter ;
  444. } ;
  445.  
  446. //-----------------------------------------------------------------------------
  447.  
  448.    // Here is the class that represents a command-line object. A command
  449.    // line object is a parsing machine (with machine states), whose parsing
  450.    // behavior may be configured at run-time by specifying various CmdFlags
  451.    // (defined below). A command-line object also contains a command-name
  452.    // and a list of CmdArg objects that correspond to the various arguments
  453.    // that are allowed to occur on the command line.
  454.    //
  455. class  CmdLine {
  456. public:
  457.    friend class CmdLineCmdArgIter;
  458.  
  459.       // Flags that define parsing behavior
  460.       //   The default flags (for Unix) are OPTS_FIRST.
  461.    enum CmdFlags {
  462.       ANY_CASE_OPTS = 0x001, // Ignore character-case for short-options
  463.       PROMPT_USER   = 0x002, // Prompt the user for missing required args
  464.       NO_ABORT      = 0x004, // Dont quit upon syntax error
  465.       OPTS_FIRST    = 0x008, // No options after positional parameters
  466.       OPTS_ONLY     = 0x010, // Dont accept short-options
  467.       KWDS_ONLY     = 0x020, // Dont accept long-options
  468.       TEMP          = 0x040, // Assume all arg-strings are temporary
  469.       QUIET         = 0x080, // Dont print syntax error messages
  470.       NO_GUESSING   = 0x100, // Dont guess if cant match an option. 
  471.                                 // Unless this flag is given, then
  472.                                 // when we see an unmatched option,
  473.                                 // we will try to see if it matches
  474.                                 // a keyword (and vice-versa).
  475.       ALLOW_PLUS    = 0x200, // Allow "+" (as well as "--") as a prefix
  476.                                 // indicating long-options.
  477.    } ;
  478.  
  479.       // Flags to convey parsing-status
  480.    enum CmdStatus {
  481.       NO_ERROR      = 0x000,  // No problems
  482.       ARG_MISSING   = 0x001,  // A required argument was not specified
  483.       VAL_MISSING   = 0x002,  // A required argument value was not specified
  484.       VAL_NOTSTICKY = 0x004,  // Value needs to be in same token
  485.       VAL_NOTSEP    = 0x008,  // Value needs to be in separate token
  486.       KWD_AMBIGUOUS = 0x010,  // An ambiguous keyword prefix was specified
  487.       BAD_OPTION    = 0x020,  // An invalid option was specified
  488.       BAD_KEYWORD   = 0x040,  // An invalid keyword was specified
  489.       BAD_VALUE     = 0x080,  // An invalid value was specified for an arg
  490.       TOO_MANY_ARGS = 0x100,  // Too many positional args were specified
  491.    } ;
  492.  
  493.       // Contructors and Destructors ...
  494.       //
  495.       //   It is not necessary to supply a command-name at construction
  496.       //   time, but one SHOULD be specified before parsing a command-line
  497.       //   or printing a usage message.
  498.       //
  499.       //   Similarly, CmdArgs are not required at construction time and may
  500.       //   even be added on the fly. All desired arguments should be added
  501.       //   before any parsing happens and before printing usage.
  502.       //
  503.       //   The order in which CmdArgs are added to a CmdLine is important
  504.       //   because for positional parameters, this specifies the order in
  505.       //   which they are expected to appear on the command-line.
  506.       //
  507.    CmdLine(const char * name =0);
  508.  
  509.    CmdLine(const char * name, CmdArg * ...);   // last arg should be NULL
  510.  
  511.    CmdLine(CmdArg * cmdarg, CmdArg * ...);     // last arg should be NULL
  512.  
  513.    virtual ~CmdLine(void);
  514.  
  515.       // Get the command name.
  516.    const char *
  517.    name(void)  const  { return  cmd_name; }
  518.  
  519.       // Specify a command name.
  520.    void
  521.    name(const char * progname);
  522.  
  523.       // Get the command description.
  524.    const char *
  525.    description(void)  const  { return  cmd_description; }
  526.  
  527.       // Specify a command description.
  528.    void
  529.    description(const char * the_description) {
  530.       cmd_description = the_description;
  531.    }
  532.  
  533.       // Append an argument
  534.    CmdLine &
  535.    append(CmdArg * cmdarg);
  536.  
  537.    CmdLine &
  538.    append(CmdArg & cmdarg)  { return  append(& cmdarg); }
  539.  
  540.       // The insertion operator (operator<<) is merely a convenient
  541.       // shorthand for the append() member function.
  542.       //
  543.    CmdLine &
  544.    operator<<(CmdArg * cmdarg)  { return  append(cmdarg) ; }
  545.  
  546.    CmdLine &
  547.    operator<<(CmdArg & cmdarg)  { return  append(& cmdarg) ; }
  548.  
  549.    //
  550.    // Messages and Status
  551.    //
  552.  
  553.       // Specify the verboseness of usage messages
  554.    enum CmdUsageLevel {
  555.       NO_USAGE      = 0,  // Dont print usage at all.
  556.       TERSE_USAGE   = 1,  // Just print command-line syntax.
  557.       VERBOSE_USAGE = 2,  // Print command-line syntax & argument-descriptions.
  558.       DEFAULT_USAGE = 3,  // Read the $USAGE_LEVEL environment variable for
  559.                              // the usage-level: 0=none, 1=terse, 2=verbose.
  560.                              // if $USAGE_LEVEL is empty or is not 0, 1, or 2
  561.                              // then VERBOSE_USAGE is used.
  562.    } ;
  563.  
  564.       // Print usage on the given output stream using the given verboseness
  565.    ostream &
  566.    usage(ostream & os, CmdUsageLevel level =DEFAULT_USAGE) const ;
  567.  
  568.       // Print usage on the CmdLine's error-outstream
  569.    ostream &
  570.    usage(CmdUsageLevel level =DEFAULT_USAGE) const ;
  571.  
  572.       // Obtain the current status of the command. The status will be
  573.       // zero if everything is alright; otherwise it will correspond
  574.       // to a combination of CmdStatus bitmasks telling us precisely
  575.       // what went wrong.
  576.       //
  577.    unsigned
  578.    status(void)  const  { return  cmd_status; }
  579.  
  580.       // Print an error message prefix on the error output stream
  581.       // associated with this command. The prefix printed is the
  582.       // basename of the command followed by a ':'.
  583.       //
  584.       // Hence error messages associated with this command may be
  585.       // printed as follows:
  586.       //
  587.       //    my_cmd.error() << "This is what went wrong!" << endl;
  588.       //
  589.       // If NOPRINT is given as a parameter, then nothing
  590.       // is printed.
  591.       //
  592.    enum { NOPRINT = 0, PRINT = 1 } ;
  593.  
  594.    ostream &
  595.    error(int  print =PRINT) const;
  596.  
  597.       // If the QUIET-flag is not set, then we need to know where
  598.       // to print any error messages (the default is cerr).
  599.       //
  600.       // Use this member function to specify the desired output stream
  601.       // for error messages.
  602.       //
  603.    void
  604.    error(ostream & os) { cmd_err = &os; }
  605.  
  606.    //
  607.    // Get & set the command-parsing-flags
  608.    //
  609.  
  610.       // Get the current set of command-flags
  611.    unsigned
  612.    flags(void) const  { return  cmd_flags; }
  613.  
  614.       // Specify a new set of command-flags
  615.    void
  616.    flags(unsigned newflags)  { cmd_flags = newflags; }
  617.  
  618.       // Set only the given command-flags
  619.    void
  620.    set(unsigned flags)  { cmd_flags |= flags; }
  621.  
  622.       // Clear only the given command-flags
  623.    void
  624.    clear(unsigned flags =~0)  { cmd_flags &= ~flags; }
  625.  
  626.    //
  627.    // We are somewhat flexible in the way we parse arguments.
  628.    // Before any parsing can occur, some preprocessing needs to
  629.    // be done. After we have parsed all the arguments, some
  630.    // post-processing needs to be done.  If you use the "parse()"
  631.    // member function, then this pre- and post- processing is
  632.    // automatically performed for you UNLESS you specify a second
  633.    // parameter of NO_PROCESSING.  If you have arguments that are
  634.    // coming from more then one input source, you will have to
  635.    // manually activate pre-processing (by calling prologue()),
  636.    // then parse all your arguments (using parse() with NO_PROCESSING
  637.    // and/or using arg_parse()), and then manually activate
  638.    // post-processing (by calling epilogue()).
  639.    //
  640.  
  641.       // Parse a set of arguments (pre- and post- processing is
  642.       // automatically performed UNLESS "NO_PROCESSING" is given
  643.       // as the second argument).
  644.       //
  645.       // Return the resultant command status.
  646.       //
  647.    enum { NO_PROCESSING = 0, AUTO_PROCESSING = 1 } ;
  648.  
  649.    unsigned
  650.    parse(CmdLineArgIter & arg_iter, int  processing =AUTO_PROCESSING) ;
  651.  
  652.       // Perform the necessary pre-processing.
  653.       // Return the resultant command status.
  654.       //
  655.    unsigned
  656.    prologue(void) ;
  657.  
  658.       // Parse a single argument (pre- and post- processing is
  659.       // NOT performed).
  660.       //
  661.    unsigned
  662.    parse_arg(const char * arg) ;
  663.  
  664.       // Perform the necessary post-processing.
  665.       // Return the resultant command status.
  666.       //
  667.    unsigned
  668.    epilogue(void) ;
  669.  
  670.    //
  671.    // Find out the number of arguments parsed so far
  672.    //
  673.  
  674.    unsigned
  675.    nargs_parsed(void) const { return cmd_nargs_parsed; }
  676.  
  677.    //
  678.    // Exception handling (well -- not really)
  679.    //
  680.  
  681.    typedef  void (* quit_func_t)(int);
  682.  
  683.       // When a fatal error is encounteredi or when parsing needs to
  684.       // terminate immediately, the quit() member function is called.
  685.       // If the programmer has used quit_handler() to setup his own
  686.       // handler-function, that that function is called; otherwise
  687.       // exit() is called with the given status.
  688.       // 
  689.    void
  690.    quit(int status);
  691.  
  692.       // Set the quit-handler. The quit-handler is a pointer to
  693.       // a function that has no return value and takes a single
  694.       // integer parameter.
  695.       //
  696.    void
  697.    quit_handler(quit_func_t  quit_func) { cmd_quit_handler = quit_func ; }
  698.  
  699.       // Get the current quit-handler (returns NULL if there isnt one)
  700.       //
  701.    quit_func_t
  702.    quit_handler(void) const { return  cmd_quit_handler; }
  703.  
  704.  
  705.    //
  706.    // Retrieve a specific argument
  707.    //
  708.  
  709.       // Retrieve an argument based on its character-name.
  710.       // Returns NULL if no argument matches the given character.
  711.       //
  712.    CmdArg *
  713.    operator[](char optchar) const { return  opt_match(optchar); }
  714.  
  715.       // Retrieve an argument based on its keyword-name.
  716.       // (if an argument has no keyword-name then we try to match its
  717.       // value name instead).
  718.       //
  719.       // Returns NULL if no argument matches the given keyword or
  720.       // the keyword is ambiguous.
  721.       //
  722.    CmdArg *
  723.    operator[](const char * keyword) const
  724.       { int ambig = 0;  return  kwd_match(keyword, -1, ambig, 1); }
  725.  
  726.    //
  727.    // Version specific information
  728.    //
  729.  
  730.       // get the release number
  731.    static  unsigned
  732.    release(void);
  733.  
  734.       // get the patchlevel number
  735.    static  unsigned
  736.    patchlevel(void);
  737.  
  738.       // get the SCCS identifier string
  739.    static  const char *
  740.    ident(void);
  741.  
  742.    //
  743.    // These next few functions are used internally but are general
  744.    // enough in purpose as to possibly be useful to others.
  745.    //
  746.  
  747.       // return type for an attempted keyword match
  748.    enum strmatch_t { str_NONE, str_PARTIAL, str_EXACT } ;
  749.  
  750.       // Try to match "attempt" against "src", if len is 0 then
  751.       // only the first "len" characters are compared.
  752.       //
  753.       // Returns str_EXACT for an exact-match str_PARTIAL for a
  754.       // partial-match, and str_NONE otherwise.
  755.       //
  756.    static  strmatch_t
  757.    strmatch(const char * src, const char * attempt, unsigned  len =0);
  758.  
  759.       // Print a hanging indented paragraph on an outstream. Long lines
  760.       // are broken at word boundaries and are warpped to line up with
  761.       // the rest of the paragraph.  The format looks like the following
  762.       // (text starts on a new line is the strlen(title) >= indent):
  763.       //
  764.       // <------------------------- maxcols ------------------------------->
  765.       // <--- margin ---><--- indent --->
  766.       //                 title           This is the first sentence.  This
  767.       //                                 is the second sentence. etc ...
  768.       //
  769.    static  void
  770.    strindent(ostream    & os,
  771.              unsigned     maxcols,
  772.              unsigned     margin,
  773.              const char * title,
  774.              unsigned     indent,
  775.              const char * text);
  776.  
  777.    //
  778.    // Debugging stuff ...
  779.    //
  780.  
  781.       // If we were compiled for dubugging, then dump this command
  782.    virtual  void
  783.    dump(ostream & os, unsigned level =0) const;
  784.  
  785.       // If we were compiled for dubugging, then dump the argument list
  786.    virtual  void
  787.    dump_args(ostream & os, unsigned level =0) const;
  788.  
  789. private:
  790.       // Private data members
  791.    unsigned          cmd_parse_state : 8 ;
  792.    unsigned          cmd_state  : 8 ;
  793.    unsigned          cmd_flags  : 16 ;
  794.    unsigned          cmd_status : 16 ;
  795.    unsigned          cmd_nargs_parsed ;
  796.    const char      * cmd_name ;
  797.    const char      * cmd_description ;
  798.    CmdArg          * cmd_matched_arg ;
  799.    CmdArgListList  * cmd_args ;
  800.    ostream         * cmd_err ;
  801.    quit_func_t       cmd_quit_handler ;
  802.  
  803.       // Disallow copying and assignment
  804.    CmdLine(const CmdLine & );
  805.  
  806.    CmdLine &
  807.    operator=(const CmdLine & );
  808.  
  809.    //
  810.    // Member functions for internal use
  811.    //
  812.  
  813.       // Specify the command syntax to use for usage messages
  814.    enum CmdLineSyntax { cmd_OPTS_ONLY = 0, cmd_KWDS_ONLY = 1, cmd_BOTH = 2 } ;
  815.  
  816.    int
  817.    handle_arg(CmdArg * cmdarg, const char * & arg);
  818.  
  819.    void
  820.    ck_need_val(void);
  821.  
  822.    CmdLineSyntax
  823.    syntax(void) const;
  824.  
  825.    unsigned
  826.    prompt_user(CmdArg * cmdarg);
  827.  
  828.    unsigned
  829.    missing_args(void);
  830.  
  831.    CmdArg *
  832.    opt_match(char optchar) const;
  833.  
  834.    CmdArg *
  835.    kwd_match(const char * kwd,
  836.              int          len,
  837.              int &        is_ambiguous,
  838.              int          match_value =0) const;
  839.  
  840.    CmdArg *
  841.    pos_match(void) const;
  842.  
  843.    unsigned
  844.    parse_option(const char * arg);
  845.  
  846.    unsigned
  847.    parse_keyword(const char * arg);
  848.  
  849.    unsigned
  850.    parse_value(const char * arg);
  851.  
  852.    ostream &
  853.    arg_error(const char * error_str, const CmdArg * cmdarg) const;
  854.  
  855.    unsigned
  856.    fmt_arg(const CmdArg * cmdarg,
  857.            char         * buf,
  858.            unsigned       bufsize,
  859.            CmdLineSyntax  syntax,
  860.            CmdUsageLevel  level) const;
  861.  
  862.    static  CmdUsageLevel
  863.    get_usage_level(void);
  864.  
  865.    unsigned
  866.    print_synopsis(CmdLineSyntax syntax,
  867.                   ostream     & os,
  868.                   int           cols) const;
  869.  
  870.    void
  871.    print_descriptions(CmdLineSyntax   syntax,
  872.                       ostream       & os,
  873.                       int             cols,
  874.                       unsigned        longest) const;
  875.  
  876. } ;
  877.  
  878.  
  879.    // "os << cmd" is equivalent to "cmd.usage(os)"
  880. inline ostream &
  881. operator <<(ostream & os, CmdLine & cmd)  { return  cmd.usage(os); }
  882.  
  883.  
  884. //-----------------------------------------------------------------------------
  885.  
  886.    // We want to provide the user with a means to iterate over all the
  887.    // arguments in the argument list of a command-line.  We will provide
  888.    // a class named "CmdLineCmdArgIter" to do this.
  889.  
  890. class  CmdLineCmdArgIter {
  891. public:
  892.    CmdLineCmdArgIter(CmdLine & cmd);
  893.  
  894.    CmdLineCmdArgIter(CmdLine * cmd);
  895.  
  896.    virtual ~CmdLineCmdArgIter(void);
  897.  
  898.       // Return the current argument and advance to the next one.
  899.       // Returns NULL if we are already at the end of the list.
  900.       //
  901.    CmdArg *
  902.    operator()(void);
  903.  
  904. private:
  905.    CmdLineCmdArgIter(const CmdLineCmdArgIter &);
  906.  
  907.    CmdLineCmdArgIter &
  908.    operator=(const CmdLineCmdArgIter &);
  909.  
  910.    CmdArgListIter * iter;
  911. } ;
  912.  
  913. #endif /* _usr_include_cmdline_h */
  914.